﻿using MetaContainer;
using Microsoft.Practices.ServiceLocation;
using NUnit.Framework;

namespace Tests.MetaContainer
{
   public abstract class ImplementationTestBase
   {
      protected abstract IMetaContainer InstanceUnderTests { get; }
      
      [Test]
      public void ChildContainerResolvesTypesRegisteredInParent()
      {
         InstanceUnderTests.Register<ITestInterface1, TestClass1A>();
         IMetaContainer childContainer = InstanceUnderTests.CreateChildContainer();
         Assert.IsNotNull(childContainer, "Unity adapter should support child containers.");

         ITestInterface1 impl = childContainer.GetInstance<ITestInterface1>();
         Assert.IsNotNull(impl, "Child containers should be able to resolve types registered in parent.");
      }

      [Test]
      public void ChildContainerUsesFactoryMethodsRegisteredInParent()
      {
         InstanceUnderTests.Register<ITestInterface1>( name => new TestClass1A());
         IMetaContainer childContainer = InstanceUnderTests.CreateChildContainer();
         Assert.IsNotNull(childContainer, "Unity adapter should support child containers.");

         ITestInterface1 impl = childContainer.GetInstance<ITestInterface1>();
         Assert.IsNotNull(impl, "Child containers should use factory method registered in parent.");

         impl = childContainer.GetInstance<ITestInterface1>("name");
         Assert.IsNotNull(impl, "Child containers should use factory method registered in parent.");
      }

       [Test]
       public void ChildContainerRegistersOwnImplementations()
       {
           InstanceUnderTests.Register<ITestInterface1>(name => new TestClass1A());
           IMetaContainer childContainer = InstanceUnderTests.CreateChildContainer();
           Assert.IsNotNull(childContainer, "Unity adapter should support child containers.");

           childContainer.Register<ITestInterface1, TestClass1B>();
           var test = childContainer.Resolve<ITestInterface1>();
           Assert.AreEqual(typeof(TestClass1B), test.GetType());
       }

       [Test, ExpectedException(typeof(ActivationException))]
       public void ParrentCannotResolveChildContainerRegistration()
       {
           InstanceUnderTests.Register<ITestInterface1>(name => new TestClass1A());
           IMetaContainer childContainer = InstanceUnderTests.CreateChildContainer();
           Assert.IsNotNull(childContainer, "Unity adapter should support child containers.");

           childContainer.Register<ITestInterface, SampleTestImpl>();
           InstanceUnderTests.Resolve<ITestInterface>();
       }

       [Test]
       public void Scope_Transient()
       {
           InstanceUnderTests.Register<ITestInterface1, TestClass1A>();
           var obj1 = InstanceUnderTests.Resolve<ITestInterface1>();
           var obj2 = InstanceUnderTests.Resolve<ITestInterface1>();
           Assert.IsFalse(obj1.Equals(obj2));
       }

       [Test]
       public void Scope_Singleton()
       {
           InstanceUnderTests.Register<ITestInterface1, TestClass1A>(Scope.Singleton);
           var obj1 = InstanceUnderTests.Resolve<ITestInterface1>();
           var obj2 = InstanceUnderTests.Resolve<ITestInterface1>();
           Assert.AreEqual(obj1, obj2);
       }

      #region Test classes and interfaces
      public interface ITestInterface1
      {         
      }

      public class TestClass1A : ITestInterface1
      {
         
      }

      public class TestClass1B : ITestInterface1
      {

      }
      #endregion
   }
}
